Page Links
An FM Receiver using gqrx and a Raspberry Pi


Overview

This page provides instructions for setting up an FM Receiver using gqrx, a Raspberry Pi, and an rtl-sdr radio dongle. This specific example includes several optional components such as the Sunfounder display, and the folded dipole antenna, which are not required. These optional items can be replaced by a standard monitor, a whip antenna, or even just a wire strung across the room. There are comments on this page about cooling the Raspberry Pi, and although my implementation may not be for everyone, some form of heat management is recommended.

_DSC1048G.png image

gqrx1.png image
gqrx running on 10" Sunfounder Display screenshot of gqrx tuned to an FM station


Hardware Used

The main hardware used to create these instructions were a Raspberry Pi 3 Model B+, and an rtl-sdr radio dongle. It should be possible to use an older Raspberry Pi, although the sample rate or FPS setting may need to be redcued. The rtl-sdr radio was selected for this example project because it is very inexpensive. These radios don't have great performance, but we're building an FM receiver, and FM stations are pretty strong so an inexpensive radio is just fine. If you already have a different radio and want to use that, there is a good chance that gqrx is compatible with it. You can check out the list of compatible hardware here.

RPi 2 Model B image
Raspberry Pi 3 B+

Edimax image
rtl-sdr (RTL2832U) TV Tuner

The extra hardware used in this example was a Sunfounder 10.1" HDMI Display, and an Outdoor FM Antenna. The Amazon link above for the rtl-sdr includes a portable telescopic dipole antenna which may be all that you need for this project. In my case, I was setting this up in the basement so reception was terrible. The outdoor antenna wasn't very expensive, and the reviews were good, so I installed one outside on the fence, ran a coax cable into the basement, and I am very happy with the results. If you decide to do something similar, don't foget that you'll need coax cable, and a coax to SMA adapter. The links are to what I used. You can use whatever you want.

RPi 2 Model B image
Backside of Sunfounder display with mounted Pi

Edimax image
Outdoor FM folded dipole antenna

Two things before moving on. First, the Sunfounder display I used was an older version, and doesn't appear to be sold anymore. The link provided above is for the newer version. It looks to be an improvement over mine (particularly only requiring one power cord now), but I can't confirm that. Second, the Raspberry Pi case mounted on the back doesn't look like the one in the Amazon product photo. That's because it isn't! The mounting option that comes with the Sunfounder display looks pretty, but has no cooling. Running GQRX will make the Pi run hot, and since things running hotter fail sooner, I decided to swap the normal mount with an iUniker case with fan. That cooled down the Pi, but it made more noise than I was happy with. Later on I replaced it with a quieter solution. I talk about this at the end of the page.

The rest of the instructions assume that whatever choices you made given the information above, that you at least have a Raspberry Pi connected to to an rtl-sdr dongle which is connected to some kind of antenna.



Installing the Software

For this example, I started with a clean installation of the 2018-10-09-raspbian-stretch.img, and performed the standard start-up configuration (i.e. language, time zone, keyboard layout, etc.). Starting with a clean image isn't required, although if you have installed previous versions of rtl-sdr or gqrx, you may have to execute a make uninstall. Since we will need to download files, make sure that you have a working internet conection before continuing.

Prior to starting any project specific changes, I made sure that I had the latest packages by executing the following:

sudo apt-get update
sudo apt-get -y upgrade
sudo reboot

Next, I disabled screen blanking, and setup screen capture. Disabling screen blanking is highly recommended for this project. After all, you're about to make a beautiful looking FM Receiver, and it would be a shame not to be able to see it all the time. Setting up screen capture is not required. I did that to be able to use [Alt-Print], which is not part of the normal raspbian-stretch keybinding, so that I could take pictures for these instructions.

In order to make the setup process easier, I created an install script to download and build all of the necessary components. I put these commands together by first manually performing the installation and recording each step into the script. Afterwards, I reset the Pi back to a clean image, ran the script, and the results were successful. The contents of the script are shown below.

Update 26-APR-2020: If you are installing on Raspbian Buster or later or an RPi4, when you get to the instructions for installing gqrx in the script below, use 'Add / Remove Software' instead under Preferences in the menu. Search for gqrx and install the 'Software defined radio receiver' package. At the time of adding this update, the gqrx installer was missing a pulseaudio dependency. After installing gqrx additionally execute the following commands.

sudo apt install pulseaudio
pulseaudio -D

#! /bin/bash
set -x #echo on

# this script must be run as the standard user. Do not use "sudo" to launch the script.
# The script will apply "sudo" only where required. Some commands like "wget" will 
# not place files in the user's directories if "sudo" is used.  


# Update the package list.   
sudo apt-get update


# install rtl-sdr
cd ~
sudo apt-get -y install git
sudo apt-get -y install cmake
sudo apt-get -y install build-essential
sudo apt-get -y install libusb-1.0-0-dev
git clone git://git.osmocom.org/rtl-sdr.git
cd rtl-sdr/
mkdir build
cd build
cmake ../ -DINSTALL_UDEV_RULES=ON
make
sudo make install
sudo ldconfig
sudo cp ../rtl-sdr.rules /etc/udev/rules.d/

# after this install, the following must be manually performed:
# sudo leafpad /etc/modprobe.d/blacklist-rtl.conf
# add this one line:
# blacklist dvb_usb_rtl28xxu
# save the file, close the editor and restart the machine.
# Test that the dongle is working by opening a terminal and typing: 
# rtl_test -t


#install gqrx
cd ~
wget https://github.com/csete/gqrx/releases/download/v2.11.5/gqrx-sdr-2.11.5-linux-rpi3.tar.xz
tar -xf gqrx-sdr-2.11.5-linux-rpi3.tar.xz
mv gqrx-sdr-2.11.5-linux-rpi3 gqrx
rm gqrx-sdr-2.11.5-linux-rpi3.tar.xz
sudo apt-get -y install gnuradio
sudo apt-get -y install libvolk1-bin
sudo apt-get -y install libusb-1.0-0
sudo apt-get -y install gr-iqbal
sudo apt-get -y install qt5-default
sudo apt-get -y install libqt5svg5
sudo apt-get -y install libportaudio2
cd gqrx
sudo cp udev/*.rules /etc/udev/rules.d/


# after the entire script has completed, you should be able to run gqrx by
# double-clicking the gqrx file in the gqrx folder. 

# To force sound out the HDMI port,  open a terminal window, and execute: 
# amixer cset numid=3 0
# To force sound out the audio port, open a terminal window, and execute:
# amixer cset numid=3 1

If you would like, you can manually type each line of the script into a terminal window to get a feel for what the script is doing. The preferred method is to copy the script into a location under the home directory in the Pi. Open a terminal window, cd into the directory, and change the permissions of the file to allow execution, and then execute the file using the following commands.

sudo chmod +x full_install_gqrx.sh
./full_install_gqrx.sh

Notice that "sudo" is not used in the command to execute the script above. That is very important. There are commands in the script, for example "wget", that must be executed as the standard user so that the files are placed in the user's home directory.

If for some reason the script doesn't work, you may want to consider the following things. First, check out the rtl-sdr website and see if any of the instructions have changed. Second, check out the gqrx for Rpi website and see if any of those instructions have changed. Third, verify that the location of the archive in the wget command of the script matches the location on the gqrx website. And finally, check the readme in the archive, to see if any of those instructions changed. If none of that helped, verify that you are starting with a 2018-10-09-raspbian-stretch.img. Starting with a different image doesn't guarantee failure, but it might explain it.

Assuming that the script completed successfully, there are still a few manual steps required to complete the installation. The first is that the generic drivers that will be loaded for the rtl28xxu TV decoder need to be blacklisted so that they don't get loaded by the operating system. To do this create a new blacklist file as administrator by typing:

sudo leafpad /etc/modprobe.d/blacklist-rtl.conf

In the newly created file, enter this line, save the file, close the editor, and reboot.

blacklist dvb_usb_rtl28xxu

Note: Although this wasn't required for me, if you have an older rtl-sdr dongle, you may have to blacklist instead (or in addition) "rtl2832" and/or "rtl2830".

After rebooting, you can verify that the blacklist step worked properly by typing this

rtl_test -t

You should see an output like this. Don't be concerned about the "PLL not locked!" or other messages at the bottom. That's normal. The fact that it was able to connect to the device and query the supported gain values, is a good thing.

scr1.png

At this point you should be able to start gqrx by double-clicking the file called gqrx in the ~/gqrx folder. If you get a prompt with multiple options, I recommend selecting the “Execute in Terminal” option. That way you can see the printed output if you need to, which can be very helpful when diagnosing problems.

Update 26-APR-2020: If you installed gqrx using 'Add / Remove Software' launch gqrx using desktop menu instead

When you launch for the first time you should get a configuration window, like the one below. In that window click the "Device" drop-down menu, and select the "Realtek RTL2838U..." device. This should automatically default the "Device string" to "rtl=0" and the "input rate" to "1800000". I would recommend not changing those values.

scr3.png

After clicking [OK], you should see something like the following screen. Before pressing start, expand the window, and change the tune frequency to something within the FM broadcast range of 88-108 MHz. In this example, I'm using 101.100.000, which is a local station near me.

scr4.png

When you press the start button and you should see something like the image below. If there are humps in the FFT display that is a good indication that everything is working. You won't hear any sound yet. That's normal. This is because the default setting for demodulation mode is AM. Change the "Mode" to "WFM (mono)". Then slide the "Gain" slider in the "Audio" area to the right a little. I usually set it below the "15" on the x-axis of the audio display. At this point you may (or may not) have sound.

scr5.png

For me, the Sunfounder display has a built-in speaker that uses HDMI audio, which is the default rasbian audio port. If you don't have HDMI audio, then you are probably using the audio jack to connect to external speakers. To make that work, type the following in a terminal window, and you should immediately get audio out the audio jack. Note that although the display shown has a speaker, it is not great for playing music. I actually used a pair of "externally powered" Harmon-Kardon speakers using the audio jack. I didn't have any USB powered speakers to try, but I don't think they would work.

amixer cset numid=3 1

If in the future you want to go back to HDMI audio, simply type this.

amixer cset numid=3 0

At this point you should have sound. If you don't, make sure that "Squelch" is set to "-150.0 dB". This should be the default setting. You should be able to reset it by pressing the [R] button next to the squelch display. If that doesn't work, try tuning into another station. If that doesn't work try rebooting, crossing your fingers, and starting gqrx again. The gqrx build for the Raspberry Pi is still experimental, although if you are repeating these instructions exactly, I have had good luck with it. Once you have sound working, continue with the rest of the instructions.

Update 26-APR-2020: If you are running Raspbian Buster or later, additionally check the speaker icon in the upper right systray. Occassionally the speaker master volume gets reset to 0. You can also select the analog audio jack or hdmi using this control.

Change to the "Input Controls" tab. For me the LNA gain defaults to maximum, which swamps everything in noise. Move the LNA slider all the way to the left, and then start moving back to the right slowly. The signals should start rising up out of the noise floor. At some point the noise floor will also begin to rise, and if you keep going you may notice another point where the noise begins to swamp the signals or other spurs begin showing up across the sprectrum. I typically keep the gain midway between these two points. After setting the LNA gain, and adjusting the audio output display by grabbing the y-axis and dragging upwards until the audio spectrum fills the display, my view looked like this.

scr6.png

Go to the "FFT Settings" tab and adjust the settings to your liking. Reducing the "Averaging" makes the FFT display much more responsive, which I like so that the difference between talking and music is more obvious. The "Panadaptor" slider adjusts the percentage of the window allocated to the FFT display and the Waterfall display. The "Pand. dB" slider has two controls that adjust the offset and gain of the FFT display. The "Wf dB" slider works the same way for the waterfall display. I also like changing the "Color" to Yellow. When I'm done making my adjustments, it looks like this.

scr7.png

Once you have it set the way you want, click on the "Fullscreen Mode" icon at the far right of the icon menu.

Congratulations! That's it. Enjoy your new FM Radio! It's a great conversation piece too.



The Effect of Nearby Stations

The one thing about SDR's is that everyone's experience is going to be slightly different. The antenna type, placement, orientation, proximity to other objects or noise sources, will all affect what you see and hear. If you want to listen to a particular station, and it isn't coming in very well, try adjusting your antenna orientation. Not only will you be able to affect how well you pick up your desired station, but you may also be able to reduce how well you pick up an undesired nearby station.

One of the first things you'll notice is that the received signal strength of the stations vary. This is typically relative to the physical distance between you and the transmitter for each particular station, as well as objects between you and the transmitter. There isn't typically much you can do about that. If you are using the telescopic dipole that comes with the rtl-sdr, try rotating it. That antenna is directional. It is usually best to fix problems using the antenna before increasing the gain of the SDR. Increasing the gain increases the level of all signals coming into the radio. If a strong signal exceeds the radio's input capabilities before you get a good signal to noise ratio on your favorite station, it will cause mixing spurs and other general badness to start appearing across the entire band.

scr10.png

Another thing to keep in mind is that the source of the noise may not always be obvious. Even though you may not "see" it on the display, the radio's front-end is still receiving the signal. For me the real problem is a station at 88.3 MHz. This station has a 5000W transmitter just a few miles from my house, and at this range it blasts in and spreads well beyond it's intended bandwidth. Even though I can't "see" this station when I'm tuned up at 101.1 MHz, the radio does, which limits my ability to increase gain. Depending on your location this may not be a problem for you, and since FM stations are generally pretty strong, getting good reception on most stations shouldn't be a problem.

scr8.png

In the future if you decide to expand into listening to "weak signals", such as ham radio bands below 30 MHz, you may want to consider getting FM and AM filters to block these high power signals.



Discussion of Sample Rate Effects

One of the largest contributors to processor CPU loading is going to be the sample rate that you select in the configuration window. To explore this a little, I created a Python script to display and record the CPU temperature and CPU loading. You can see the cpu_monitor window at the lower-right corner of the waterfall display of the screenshots below. For the experiment I selected 3 different sample rates of 1200000, 1800000, and 2400000. In GQRX, these selections change the amount of spectrum bandwidth displayed. For example, when 1.8 Msps is selected, GQRX will display 1.8 MHz. These selections also change how hard the processor has to work, and how hot the processor gets.

For the first part of the experiment, and the screenshots below, I turned off the fan. With no fan, and no CPU load, the Raspberry Pi ran at about 45C. When GQRX was started with a 1.2 Msps sample rate, the temperature jumped to about 60C, and the CPU average was about 46%.

OPT2_NoFan_830px.png

When the sample rate was increased to 1.8 Msps, the temperature jumped to about 64C, and average CPU loading increased to about 67%.

OPT3_NoFan_830px.png

When the sample rate was increased again to 2.4 Msps, the temperature jumped to about 67C, and average CPU loading increased to about 73%.

OPT4_NoFan_830px.png

For the second part of the experiment, the sequence was repeated, this time with the fan solution shown below running at 3.5Vdc (not the iUniker case with fan). The baseline temperature for the Raspberry Pi with no load dropped to 30C, and the temperature for each of the sample rates above dropped to 39C, 41C and 43C respectively.

CPUTemp.png

Fan Modification

I found the fan on the iUniker case to be too noisy which detracted from the presentation of the FM Receiver. I made the following modifications to my project in order to achieve a nearly noise-less fan solution. Using the iUniker case as template, I cut out two new top and bottom enclosure parts using a 93 mil Lexan polycarbonate sheet from Home Depot or Lowe's. I added 4 1/4 inch Nylon spacers to add space for the screws underneath the hex standoffs that I re-used from the iUniker case.

FanMod1.png

I mounted the Raspberry Pi onto the bottom sheet using the Sunfounder Display hardware.

FanMod2.png

I then added the top sheet which I modified to support a Sunon MagLev fan, and an adjustable switch mode power supply. The Raspberry Pi header pins (Pin 4 = 5V, Pin 6 = GND) were used to supply power to the adjustable supply input, and the supply output was connected to the fan wires.

FanMod3.png

Here is another view. The full manufacturer's part number for the fan is MB50100V2-000U-A99. This is a 50mm x 50mm x 10mm, 5 VDC, Vapo-bearing, medium speed fan. (I would have chosen a low-speed fan if any had been in stock). The minimum starting voltage at 25°C is specified as 3.5 VDC. Although my particular fan started fine at lower voltages, 3.5 VDC was selected to provide consistent starting behavior. The adjustable supply link provided was for a 6-pack of supplies. Althought that is overkill for a single project, my experience with these has been that only about 50% of these supplies function, so it's more like a 3-pack.

FanMod4.png

CPU Loading

The data logging of the cpu_monitor script provided an interesting insight into how the Raspberry Pi performs load sharing. The graph below shows the cpu loading with gqrx running at 1.2, 1.8, and 2.4 Msps sample rates. At a glance, an average CPU usage just above 70% would seem to suggest that a Raspberry Pi3 B+ should be able to support sample rates higher than 2.4 Msps. This is actually not correct.

CPULoad.png

The Raspberry Pi has a quad-core processor that employs CPU load sharing. The plot below shows the instantaneous CPU usage for each of the four cores during the experiment at 2.4 Msps. It can be seen that although the average is only just above 70%, the peak loading of individual cores is just below 100%. Increasing in sample rate of gqrs above 2.4 Msps results in occasional 100% CPU loads and data losses in the audio stream. When considering whether older Pis can be used for this project, it will be the CPU loading issue more than temperature that determines the answer. At some point the sample rate may have to be lowered to a point that the result becomes unimpressive.

CPUSpread.png